package com.xjh.utils.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Maps;

//import org.dom4j.Document;
//import org.dom4j.DocumentException;
//import org.dom4j.DocumentHelper;
//import org.dom4j.Element;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class XmlUtil {
 // 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
//    public static Map doXMLParse(String strxml) {
//        Document document = null;
//        try {
//            document = DocumentHelper.parseText(strxml);
//        } catch (DocumentException e) {
//            e.printStackTrace();
//        }
//        Element rootElement = document.getRootElement();
//        @SuppressWarnings("unchecked")
//        List<Element> elements = rootElement.elements();
//        Map<String, String> map = Maps.newHashMap();
//        for (org.dom4j.Element element : elements) {
//            map.put(element.getName(), element.getText());
//        }
//        return map;
//    }

    public static JSONObject xml2Json(String xmlStr) throws JDOMException, IOException {
        if (StringUtils.isEmpty(xmlStr)) {
            return null;
        }
        xmlStr = xmlStr.replaceAll("\\\n", "");
        byte[] xml = xmlStr.getBytes("UTF-8");
        JSONObject json = new JSONObject();
        InputStream is = new ByteArrayInputStream(xml);
        SAXBuilder sb = new SAXBuilder();
        Document doc = sb.build(is);
        Element root = doc.getRootElement();
        json.put(root.getName(), iterateElement(root));

        return json;
    }

    private static JSONObject iterateElement(Element element) {
        List<Element> node = element.getChildren();
        JSONObject obj = new JSONObject();
        List list = null;
        for (Element child : node) {
            list = new LinkedList();
            String text = child.getTextTrim();
            if (StringUtils.isBlank(text)) {
                if (child.getChildren().size() == 0) {
                    continue;
                }
                if (obj.containsKey(child.getName())) {
                    list = (List) obj.get(child.getName());
                }
                list.add(iterateElement(child)); //遍历child的子节点
                obj.put(child.getName(), list);
            } else {
                if (obj.containsKey(child.getName())) {
                    Object value = obj.get(child.getName());
                    try {
                        list = (List) value;
                    } catch (ClassCastException e) {
                        list.add(value);
                    }
                }
                if (child.getChildren().size() == 0) { //child无子节点时直接设置text
                    obj.put(child.getName(), text);
                } else {
                    list.add(text);
                    obj.put(child.getName(), list);
                }
            }
        }
        return obj;
    }

    /**
     * 功能说明：把xml字符串解析为实体类的对象
     * 修改说明：
     * @author peijiang.Huang
     * @date 2021-08-23
     * @param xml 要解析的xml字符串
     * @param c 解析的目标类型
     * @return 返回对应T类型的对象
     * @throws JAXBException
     */
    public static <T> T xmlToEntity(String xml, Class<T> c) throws JAXBException {
//		T result = c.newInstance();
        JAXBContext context = JAXBContext.newInstance(c);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        T result = (T)unmarshaller.unmarshal(new StringReader(xml));
        return result;
    }
    @SuppressWarnings("unchecked")
    public static Map<String, String> parseXml(final String msg) {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        try (InputStream inputStream = new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8.name()))) {
            // 读取输入流
            SAXReader reader = new SAXReader();
            org.dom4j.Document document = reader.read(inputStream);
            // 得到xml根元素
            org.dom4j.Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<org.dom4j.Element> elementList = root.elements();

            // 遍历所有子节点
            for (org.dom4j.Element e : elementList) {
                map.put(e.getName(), e.getText());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }





    public static void main(String[] args) throws IOException, JDOMException {
        String xmlData = "<xml>\n" +
                "  <ToUserName><![CDATA[ww1cSD21f1e9c0caaa]]></ToUserName>\n" +
                "  <FromUserName><![CDATA[sys]]></FromUserName>\n" +
                "  <CreateTime>1571732272</CreateTime>\n" +
                "  <MsgType><![CDATA[event]]></MsgType>\n" +
                "  <Event><![CDATA[sys_approval_change]]></Event>\n" +
                "  <AgentID>3010040</AgentID>\n" +
                "  <ApprovalInfo>\n" +
                "    <SpNo>201910220003</SpNo>\n" +
                "    <SpName><![CDATA[示例模板]]></SpName>\n" +
                "    <SpStatus>1</SpStatus>\n" +
                "    <TemplateId><![CDATA[3TkaH5KFbrG9heEQWLJjhgpFwmqAFB4dLEnapaB7aaa]]></TemplateId>\n" +
                "    <ApplyTime>1571728713</ApplyTime>\n" +
                "    <Applyer>\n" +
                "      <UserId><![CDATA[WuJunJie]]></UserId>\n" +
                "      <Party><![CDATA[1]]></Party>\n" +
                "    </Applyer>\n" +
                "    <SpRecord>\n" +
                "      <SpStatus>1</SpStatus>\n" +
                "      <ApproverAttr>2</ApproverAttr>\n" +
                "      <Details>\n" +
                "        <Approver>\n" +
                "          <UserId><![CDATA[WangXiaoMing]]></UserId>\n" +
                "        </Approver>\n" +
                "        <Speech><![CDATA[]]></Speech>\n" +
                "        <SpStatus>1</SpStatus>\n" +
                "        <SpTime>0</SpTime>\n" +
                "      </Details>\n" +
                "      <Details>\n" +
                "        <Approver>\n" +
                "          <UserId><![CDATA[XiaoGangHuang]]></UserId>\n" +
                "        </Approver>\n" +
                "        <Speech><![CDATA[]]></Speech>\n" +
                "        <SpStatus>1</SpStatus>\n" +
                "        <SpTime>0</SpTime>\n" +
                "      </Details>\n" +
                "    </SpRecord>\n" +
                "    <SpRecord>\n" +
                "      <SpStatus>1</SpStatus>\n" +
                "      <ApproverAttr>1</ApproverAttr>\n" +
                "      <Details>\n" +
                "        <Approver>\n" +
                "          <UserId><![CDATA[XiaoHongLiu]]></UserId>\n" +
                "        </Approver>\n" +
                "        <Speech><![CDATA[]]></Speech>\n" +
                "        <SpStatus>1</SpStatus>\n" +
                "        <SpTime>0</SpTime>\n" +
                "      </Details>\n" +
                "    </SpRecord>\n" +
                "    <Notifyer>\n" +
                "      <UserId><![CDATA[ChengLiang]]></UserId>\n" +
                "    </Notifyer>\n" +
                "    <Comments>\n" +
                "      <CommentUserInfo>\n" +
                "        <UserId><![CDATA[LiuZhi]]></UserId>\n" +
                "      </CommentUserInfo>\n" +
                "      <CommentTime>1571732272</CommentTime>\n" +
                "      <CommentContent><![CDATA[这是一个备注]]></CommentContent>\n" +
                "      <CommentId><![CDATA[6750538708562308220]]></CommentId>\n" +
                "    </Comments>\n" +
                "    <StatuChangeEvent>10</StatuChangeEvent>\n" +
                "  </ApprovalInfo>\n" +
                "</xml>";

        JSONObject jsonObject = xml2Json(xmlData);
        Map map = JSON.parseObject(jsonObject.toJSONString(), Map.class);
        System.out.println(jsonObject);
        System.out.println(map.get("xml"));
        System.out.println(parseXml(xmlData));
       // ApprovalInfo是list嵌套结构，解析不出来，只能获取第一层
        Map<String, String> stringStringMap = parseXml(xmlData);
        System.out.println(stringStringMap.get("ToUserName"));//
        // ApprovalInfo的东西丢了，但是不会报错，再转就会报错比如下面两行

//        System.out.println( JSON.parseObject(stringStringMap.get("ApprovalInfo")));
//        JSONArray approvalInfo = JSON.parseArray(stringStringMap.get("ApprovalInfo"));
//        System.out.println("approvalInfo"+approvalInfo);




    }

}
